package cn.fz.securityquickstart.service.impl;

import cn.fz.securityquickstart.entity.User;
import cn.fz.securityquickstart.mapper.UserMapper;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import jakarta.annotation.Resource;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.userdetails.UserDetails;
import org.springframework.security.core.userdetails.UserDetailsService;
import org.springframework.security.core.userdetails.UsernameNotFoundException;

import java.util.ArrayList;
import java.util.Collection;
import java.util.concurrent.ArrayBlockingQueue;

/**
 * 三、基于数据库的用户认证
 * 3.1 认证流程
 * 通过之前基于内存认证分析，我们知道。只要实现UserDetailsService 接口的loadUserByUsername 方法就可以从数据库中获取用户信息。
 *
 *
 * 程序启动时：
 *
 * 创建DBUserDetailsManager类，实现接口 UserDetailsService 接口
 * 在应用程序中初始化这个类的对象，使springsecurity不再从内存中获取用户信息，而是通过我们自己实现类从数据库中查询用户信息。

 * 校验用户时：
 *
 * SpringSecurity自动使用DBUserDetailsManager的loadUserByUsername方法从数据库中获取User对象
 * 在UsernamePasswordAuthenticationFilter过滤器中的attemptAuthentication方法中将用户输入的用户名密码和从数据库中获取到的用户信息进行比较，进行用户认证

 * 3.2 创建DBUserDetailsManager
 * 我们在service包下创建DBUserDetailsManager 来实现UserDetailsService 接口，替换从内存中获取用户信息。代码如下
 *
 * 3.3 初始化UserDetailsService
 * 说了一堆理论，那么我们怎么才能让springsecurity不从内存获取用户信息，而是通过上一步创建的DBUserDetailsManager 来查询用户信息。
 * 接下来的就比较关键了，我们只需创建一个WebSecurityConfig,然后创建基于数据库的用户管理器dbUserDetailsManager即可
 *
 * 当然我们也可以直接在DBUserDetailsManager类上添加@Component注解,也能实现同样的效果
 *
 * 作者：程序员晓凡
 * 链接：https://juejin.cn/post/7500421098787192883
 * 来源：稀土掘金
 * 著作权归作者所有。商业转载请联系作者获得授权，非商业转载请注明出处。
 */
public class DBUserDetailsManager implements UserDetailsService {
    @Resource
    private UserMapper userMapper;

    @Override
    public UserDetails loadUserByUsername(String username) throws UsernameNotFoundException {
        QueryWrapper<User> queryWrapper = new QueryWrapper<>();
        // 使用username构造查询条件
        QueryWrapper<User> wrapper = queryWrapper.eq("username", username);
        // 由于用户名不能重复，所以我们使用selectOne查询用户信息即可
        User user = userMapper.selectOne(wrapper);
        if (user == null) {
            throw new UsernameNotFoundException("用户【"+username+"】不存在");
        }
        // 由于现在还没有权限信息，所以我们构造一个空的权限信息
        Collection<GrantedAuthority> authorities = new ArrayList<>();
        return new org.springframework.security.core.userdetails.User(
                user.getUsername(),
                user.getPassword(),
                user.getEnabled(),
                true, //用户账户是否没过期
                true, //用户凭证是否没过期
                true, //用户是否未被锁定
                authorities //用户权限信息
        );
    }
}
